
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
	<meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test XSeq</title>
    <script src="xlib.js"></script>
	<style>
	</style>
  </head>  
  <body>
    <div id="result"></div>
    <script>
      const XSeq = XLIB.XSeq
      const Seq = XLIB.Seq, repeat = XLIB.repeat 

let error_count = 0, tc_count = 0, log = ""

function assert(criteria, fail_msg, succ_msg=""){
  tc_count++
  
  if( criteria ){
    log += `<p>${succ_msg}</p>`
  }else{
    error_count++
    log += `<p>${fail_msg}</p>`
    console.error( fail_msg )
  }
}


      // ==========  repeat测试
      {
        const r1 = repeat(5, (i)=>100)
        console.assert( r1.toString()===[100,100,100,100,100].toString(), `一维repeat测试失败` )

        const r2 = repeat([2,3], (p)=>10)
        for( let i=0; i<2; i++ )
          console.assert( r2[i].toString()===[10,10,10].toString(), `二维repeat测试失败: ${r2[i]}!=${[10,10,10]}` )

        const r3 = repeat([2,3,4], (p)=>5)
        for( let i=0; i<2; i++ ) for( let j=0; j<3; j++ )
          console.assert( r3[i][j].toString()===[5,5,5,5].toString(), `二维repeat测试失败: ${r3[i][j]}!=${[5,5,5,5]}` )
          
      }

      // ======== 基本构建函数测试
      let s = Seq([1,2,3,4,5,6])
      console.assert( s.dimSizes.toString() === [6].toString(), `维度尺寸错误` )
      console.assert( s.dimGaps.toString() === [1].toString(), `维度间距错误` )

      s = Seq(Array(24).fill(0).map((_,i)=>i), {dimSizes:[2,3,4]})
      console.assert( s.dimSizes.toString() === [2,3,4].toString(), `维度尺寸错误` )
      console.assert( s.dimGaps.toString() === [12,4,1].toString(), `维度间距错误。Expect: ${[12,4,1]}; Real: ${s.dimGaps}` )

// ======== len测试
{
  let s = Seq(Array(24).fill(0).map((_,i)=>i), {dimSizes:[2,3,4]})
  console.assert( s.len()===24, `XSeq.len()测试失败: ${s.len()}!=24` )
  s = Seq(Array(24).fill(0).map((_,i)=>i), {dimSizes:[6,4]})
  console.assert( s.len()===24, `XSeq.len()测试失败: ${s.len()}!=24` )
  s = Seq(Array(24).fill(0).map((_,i)=>i))
  console.assert( s.len()===24, `XSeq.len()测试失败: ${s.len()}!=24` )
}

      // ======== fromSeq测试
      s = XLIB.XSeq.fromSeq( [[[0,1,2,3],[4,5,6,7],[8,9,10,11]],[[12,13,14,15],[16,17,18,19],[20,21,22,23]]] )
      console.assert( s.dimSizes.toString() === [2,3,4].toString(), `维度尺寸错误` )
      console.assert( s.dimGaps.toString() === [12,4,1].toString(), `维度间距错误。Expect: ${[12,4,1]}; Real: ${s.dimGaps}` )
      console.assert( s.arr.toString() === Array(24).fill(0).map((_,i)=>i).toString(), `内容比较错误。当前内容：${s.arr}` )

      // ======== toSeq测试
      s = Seq(Array(24).fill(0).map((_,i)=>i), {dimSizes:[2,3,4]})
      r = s.toSeq()
      e = [[[0,1,2,3],[4,5,6,7],[8,9,10,11]], [[12,13,14,15],[16,17,18,19],[20,21,22,23]]]
      console.assert( r.toString() === e.toString(), `toSeq错误。期望: ${e}; 实际: ${r}` )

// ========  Fill测试
{
  const s1 = Seq([0,1,2,3])
  const res = s1.fill([6], 100)
  assert( res.data().toString() === [0,1,2,3,100,100].toString(), `一维fill测试失败: ${res.arr}!=[0,1,2,3,100,100]` )
}



      // ======== get测试
      s = Seq( Array(24).fill(0).map((_,i)=>i+100), {dimSizes:[2,3,4]} )
      for( let i=0; i<2; i++ ) for( let j=0; j<3; j++ ) for( let k=0; k<4; k++ ){
        const v = s.get( i,j,k )
        const e = i * 12 + j * 4 + k + 100
        console.assert( v === e, `get测试错误。期望: ${e}; 实际: ${v}` )
      }

// ======== set测试
{
  const s = (Seq( Array(24).fill(0).map((_,i)=>i), {dimSizes:[2,3,4]} )).set(1,1,1, 200)
  const v = s.get(1,1,1)
  assert( v === 200, `set测试错误。期望: 200; 实际: ${v}` )

  // ==== 数组Copy
  const s2 = Seq([0,0,0,0])
  s2.set( Seq(['X','Y','Z','R']) )
  assert( s2.data().toString()===['X','Y','Z','R'].toString(), `数组Copy错误：${s2.arr}!=${['X','Y','Z','R']}` )
}

      // ======== foreach测试
      s = (Seq( Array(24).fill(0).map((_,i)=>i), {dimSizes:[2,3,4]} ))
      r = [[0,4,8],[1,5,9],[2,6,10],[3,7,11],[12,16,20],[13,17,21],[14,18,22],[15,19,23]]
      cnt = 0
      s.foreach( (cs, p) => {
        console.assert( cs.toSeq().toString() === r[cnt++].toString(), `foreach比较错误` )
      }, [1] )

      // ======== Separate测试
      s = (Seq( Array(24).fill(0).map((_,i)=>i), {dimSizes:[2,3,4]} ))
      r = s.increase(0,2)
			console.assert( s.arr.toString()===r.arr.toString() )
			console.assert( s.ofst===r.ofst )
			console.assert( r.dimSizes.toString()===[2,4].toString() )
			console.assert( r.dimGaps.toString()===[12,1].toString() )

      // ======================================================================================================
      // ======== 迭代器测试
      // ======================================================================================================
      s = (Seq( Array(24).fill(0).map((_,i)=>i+100), {dimSizes:[2,3,4]} )).increase(0,2)
      r = [100,101,102,103,112,113,114,115], cnt = 0, pos = [[0,0],[0,1],[0,2],[0,3],[1,0],[1,1],[1,2],[1,3]]
			for( let it of s.iter() ){
        // 迭代器信息检测
        console.assert( it.xseq === s, "迭代测试失败：XSeq指针值向错误" )
        console.assert( it.value() === r[cnt], `迭代器值测试失败: cnt=${cnt}; ${it.value()}!=${r[cnt]}`)
        console.assert( it.ptr === r[cnt]-100, `迭代器物理位置测试失败：cnt=${cnt}; ${it.ptr}!=${r[cnt]-100}` )
        // 子XSeq检测
        const c = it.childSeq()
        console.assert( c.arr.toString()===s.arr.toString(), `迭代测试失败：子Seq内容错误。${c.arr}!=${s.arr}` )
        console.assert( c.dimSizes.toString()===[3].toString(), `迭代测试失败: 子Seq尺寸错误。${c.dimSizes}!=[3]` )
        console.assert( c.dimGaps.toString()===[4].toString(), `迭代测试失败: 子Seq间隔错误。${c.dimGaps}!=[4]` )
        console.assert( c.ofst===it.ptr, `迭代测试失败: 子Seq偏移错误。${c.ofst}!=${it.ptr}` )

        cnt++
			}
      console.assert( cnt === r.length, `迭代器测试失败：迭代个数不对。${cnt}!=${r.length}` )

      // ======== 迭代器偏移测试
      s = Seq( Array(24).fill(0).map((_,i)=>i+100), {dimSizes:[4,6]} ).decrease(1)
			it = new XLIB.XSeq.Iter(s)
			// 前进测试
			let curr = 0, ptrs = [0,6,12,18], poss = [[0],[1],[2],[3]]
			const ofsts = [1,2,5,3,4,-1,-3,-4,-5]
			for( let ofst of ofsts ){
				const r_val = it.addOfst(ofst)
				const nxt = curr + ofst
				const e_of = nxt >= 4 || nxt < 0
				const e_pos = (nxt % 4 + 4)%4
				console.assert( e_of===it.overflow, `迭代器偏移测试失败: ofst=${ofst}; ${e_of}!=${it.overflow}` )
				console.assert( ptrs[e_pos]===it.ptr, `迭代器偏移测试失败: ofst=${ofst}; ${ptrs[e_pos]}!=${it.ptr}` )
				console.assert( poss[e_pos].toString()===it.pos.toString(), `迭代器偏移测试失败: ofst=${ofst}` )
        curr = e_pos
			}
      

// ======== iterN: 正向迭代测试
{
  const s = Seq( Array(24).fill(0).map((_,i)=>i+100), {dimSizes:[4,6]} ).decrease(1)
  for( let step of [1, 3] ){

    // RR迭代测试
    let pos = 5, cnt = 0   // 初始位置
    for( let it of s.iterN({st:[pos], N:30, isRR:true, step:step}) ){
      console.assert( it.ptr===(pos+cnt*step)%4*6, `iterN测试失败：iter.ptr偏移错误。${it.ptr}!=${(pos+cnt*step)%4*6} when cnt=${cnt} & step=${step}` )
      console.assert( it.pos.toString()===[(pos+cnt*step)%4].toString(), `iterN测试失败：iter.pos错误。${it.pos}!=[${(pos+cnt*step)%4}] when cnt=${cnt} & step=${step}` )
      cnt++
    }
    console.assert( cnt===30, `iterN测试失败：测试次数不对。${cnt}!=30` )

    // 非RR迭代测试
    pos = 1, cnt = 0
    for( let it of s.iterN({st:[pos], N:30, isRR:false, step:step}) ){
      cnt++
    }
    console.assert( cnt===step==1?3:1, `iterN测试失败：测试次数不对。${cnt}!=${step==1?3:1}` )

  }
}

// ========  iterN：过滤条件criteria测试
{
  let r = []
  for( let it of Seq([1,2,3,4,5,6,7]).iterN({N:8, isRR:false, criteria:(it)=>it.value()%2==0}) ){
    r.push( it.value() )
  }
  console.assert( r.toString()===[2,4,6].toString(), `iterN: 过滤条件criteria测试失败。${r}!=${[2,4,6]}` )
}
      

      // ======================================================================================================
      // 降维测试
      // ======================================================================================================
      s = Seq( Array(24).fill(0).map((_,i)=>i+100), {dimSizes:[2,3,4]} )

      // ==== 降1维测试
      dimSize = [[3,4], [2,4], [2,3]], dimGaps = [[4,1], [12,1], [12,4]]
      for( let dim=0; dim<3; dim++ ){
        const ds = s.decrease(dim)    // 把第dim个维度降维
        console.assert( ds.arr.toString()===s.arr.toString(), `降维测试失败` )
        console.assert( ds.ofst===s.ofst, `降维测试失败` )
        console.assert( ds.dimSizes.toString()===dimSize[dim].toString(), `降维测试dimSize失败` )
        console.assert( ds.dimGaps.toString()===dimGaps[dim].toString(), `降维测试dimGap失败` )
      }

      // ==== 降2维测试
      const ds = s.decrease(0,2)
      console.assert( ds.arr.toString()===s.arr.toString(), `降维测试失败` )
      console.assert( ds.ofst===s.ofst, `降维测试失败` )
      console.assert( ds.dimSizes.toString()===[3].toString(), `降2维测试dimSize失败` )
      console.assert( ds.dimGaps.toString()===[4].toString(), `降2维测试dimGap失败` )
      console.assert( ds.associate.sizes.toString() === [2,4].toString(), `降维测试失败：伴随尺寸错误。${ds.associate.sizes}!=[3]` )
      console.assert( ds.associate.gaps.toString()===[12,1].toString(), `降维测试失败。Gaps错误。${ds.associate.gaps}!=[4]` )

      // ======================================================================================================
      // Reduce测试

      // ==== 普通数组Reduce测试
      s = Seq([1,2,3,4,5,6,7,8,9,10])
      r = s.reduce( (l,c) => l+c )
      console.assert( r === 55, `普通数组Reduce测试失败: ${r}!=55` )

      // ==== 整个XSeg Reduce测试
      s = Seq([1,2,3,4,5,6,7,8,9], {dimSizes:[3,3]})
      r = s.reduce( (l,c) => l+c )
      console.assert( r === 45, `XSeq Reduce测试失败: ${r}!=45` )
      
      // ==== 一维XSeq Recuce测试
      s = Seq([1,2,3,4,5,6,7,8,9], {dimSizes:[3,3]}).decrease(1)
      r = s.reduce( (l,c) => l+c )
      console.assert( r === 12, `XSeq Reduce测试失败: ${r}!=12` )

// ======================================================================================================
if( error_count==0 ) console.log(`%cSuccess: All Test Case Pass!`, 'color:green')

const rst = document.getElementById("result")
rst.appendChild(document.createTextNode(`成功率: ${tc_count-error_count}/${tc_count}`))
const logE = document.createElement("div")
logE.innerHTML = log
rst.appendChild(logE)

    </script>
  </body>
</html>
    
